﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;

namespace pcmap
{
    public partial class Form1 : Form
    {
        //int px = 428;
        //int py = 219;
        //int px = 2;
        //int py = 2;

        double _dx = -127;
        double _dy = 37;

        int _lv = 9;

        DateTime dt;
        public int gps;
        public int num;
        public double hdop;
        public double hight;
        public double hightdiff;
        public double velocity;
        public double degree;

        bool _change = false;

        public string _mapDir = "g:\\map\\Pdamap\\";
        public string _gpsPort = "COM5";
        public string _gpsSpeed = "4800";
        public string _gpsConnect;
        public bool _netConnect = false;

        public int _count;

        public Form1()
        {
            InitializeComponent();
            menuItem8.Checked = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            loadSetting();
            gpsSetting();
            mapShow();
        }

        private void loadSetting()
        {
            try
            {
                using (TextReader confRd = new StreamReader("PcMap.conf"))
                {
                    string rl;
                    while ((rl = confRd.ReadLine()) != null)
                    {
                        string[] sp = rl.Split('=');
                        if (sp.Count() != 2)
                        {
                            continue;
                        }
                        if (sp[0] == "MapDir")
                        {
                            _mapDir = sp[1];
                        }
                        if (sp[0] == "GpsPort")
                        {
                            _gpsPort = sp[1];
                        }
                        if (sp[0] == "GpsSpeed")
                        {
                            _gpsSpeed = sp[1];
                        }
                        if (sp[0] == "GpsConnect")
                        {
                            _gpsConnect = sp[1];
                        }
                        if (sp[0] == "X")
                        {
                            _dx = double.Parse(sp[1]);
                        }
                        if (sp[0] == "Y")
                        {
                            _dy = double.Parse(sp[1]);
                        }
                        if (sp[0] == "Lv")
                        {
                            _lv = int.Parse(sp[1]);
                        }
                    }
                }
            }
            catch
            {
            }
        }

        private void saveSetting()
        {
            using (TextWriter confWr = new StreamWriter("PcMap.conf"))
            {
                confWr.WriteLine("MapDir={0}", _mapDir);
                confWr.WriteLine("GpsPort={0}", _gpsPort);
                confWr.WriteLine("GpsSpeed={0}", _gpsSpeed);
                confWr.WriteLine("GpsConnect={0}", _gpsConnect);
                confWr.WriteLine("X={0}", _dx);
                confWr.WriteLine("Y={0}", _dy);
                confWr.WriteLine("Lv={0}", _lv);
            }
        }

        private void gpsSetting()
        {
            bool isOpen = serialPort1.IsOpen;
            if (isOpen)
            {
                serialPort1.Close();
            }
            serialPort1.PortName = _gpsPort;
            serialPort1.BaudRate = int.Parse(_gpsSpeed);
            if (isOpen)
            {
                serialPort1.Open();
            }
        }


        private void mapShow()
        {
            double lim = (2 << (_lv - 1)) * 256;

            double x = (0.5 - _dx / 360) * lim;

            double phi = Math.PI * _dy / 180;
            double dv = 0.5 * Math.Log((1 + Math.Sin(phi)) / (1 - Math.Sin(phi)));
            double y = (1 - dv / Math.PI) / 2 * lim;

            int px = (int)(x / 256);
            int py = (int)(y / 256);

            int mx = (int)x % 256;
            int my = (int)y % 256;

            _count = 0;

            //if (mx > 128)
            //{
            //    if (my > 128)
            //    {
                    pictureBox11.Image = getImg(px - 2, py - 2);
                    pictureBox12.Image = getImg(px - 1, py - 2);
                    pictureBox13.Image = getImg(px + 0, py - 2);
                    pictureBox14.Image = getImg(px + 1, py - 2);
                    pictureBox15.Image = getImg(px + 2, py - 2);
                    pictureBox21.Image = getImg(px - 2, py - 1);
                    pictureBox22.Image = getImg(px - 1, py - 1);
                    pictureBox23.Image = getImg(px + 0, py - 1);
                    pictureBox24.Image = getImg(px + 1, py - 1);
                    pictureBox25.Image = getImg(px + 2, py - 1);
                    pictureBox31.Image = getImg(px - 2, py - 0);
                    pictureBox32.Image = getImg(px - 1, py - 0);
                    pictureBox33.Image = getImg(px + 0, py - 0);
                    pictureBox34.Image = getImg(px + 1, py - 0);
                    pictureBox35.Image = getImg(px + 2, py - 0);
                    pictureBox41.Image = getImg(px - 2, py + 1);
                    pictureBox42.Image = getImg(px - 1, py + 1);
                    pictureBox43.Image = getImg(px + 0, py + 1);
                    pictureBox44.Image = getImg(px + 1, py + 1);
                    pictureBox45.Image = getImg(px + 2, py + 1);
                    pictureBox51.Image = getImg(px - 2, py + 2);
                    pictureBox52.Image = getImg(px - 1, py + 2);
                    pictureBox53.Image = getImg(px + 0, py + 2);
                    pictureBox54.Image = getImg(px + 1, py + 2);
                    pictureBox55.Image = getImg(px + 2, py + 2);

                    pictureBox11.Location = new Point(64  - mx, 64 - my);
                    pictureBox12.Location = new Point(320 - mx, 64 - my);
                    pictureBox13.Location = new Point(576 - mx, 64 - my);
                    pictureBox14.Location = new Point(832 - mx, 64 - my);
                    pictureBox15.Location = new Point(1088- mx, 64 - my);

                    pictureBox21.Location = new Point(64 - mx, 320 - my);
                    pictureBox22.Location = new Point(320 - mx, 320 - my);
                    pictureBox23.Location = new Point(576 - mx, 320 - my);
                    pictureBox24.Location = new Point(832 - mx, 320 - my);
                    pictureBox25.Location = new Point(1088 - mx, 320 - my);

                    pictureBox31.Location = new Point(64 - mx, 576 - my);
                    pictureBox32.Location = new Point(320 - mx, 576 - my);
                    pictureBox33.Location = new Point(576 - mx, 576 - my);
                    pictureBox34.Location = new Point(832 - mx, 576 - my);
                    pictureBox35.Location = new Point(1088 - mx, 576 - my);

                    pictureBox41.Location = new Point(64 - mx, 832 - my);
                    pictureBox42.Location = new Point(320 - mx, 832 - my);
                    pictureBox43.Location = new Point(576 - mx, 832 - my);
                    pictureBox44.Location = new Point(832 - mx, 832 - my);
                    pictureBox45.Location = new Point(1088 - mx, 832 - my);

                    pictureBox51.Location = new Point(64 - mx, 1088 - my);
                    pictureBox52.Location = new Point(320 - mx, 1088 - my);
                    pictureBox53.Location = new Point(576 - mx, 1088 - my);
                    pictureBox54.Location = new Point(832 - mx, 1088 - my);
                    pictureBox55.Location = new Point(1088 - mx, 1088 - my);

                    //pictureBox21.Location = new Point(64 - mx, 320 - my);
                    //pictureBox22.Location = new Point(320 - mx, 320 - my);
                    //pictureBox23.Location = new Point(576 - mx, 320 - my);
                    //pictureBox31.Location = new Point(64 - mx, 576 - my);
                    //pictureBox32.Location = new Point(320 - mx, 576 - my);
                    //pictureBox33.Location = new Point(576 - mx, 576 - my);

                    //pictureBox11.Location = new Point(120 - mx, 120 - my);
                    //pictureBox12.Location = new Point(376 - mx, 120 - my);
                    //pictureBox21.Location = new Point(120 - mx, 376 - my);
                    //pictureBox22.Location = new Point(376 - mx, 376 - my);
            //    }
            //    else
            //    {
            //        pictureBox11.Image = getImg(px - 1, py - 1);
            //        pictureBox12.Image = getImg(px + 0, py - 1);
            //        pictureBox13.Image = getImg(px + 1, py - 1);
            //        pictureBox21.Image = getImg(px - 1, py);
            //        pictureBox22.Image = getImg(px + 0, py);
            //        pictureBox23.Image = getImg(px + 1, py);
            //        pictureBox31.Image = getImg(px - 1, py + 1);
            //        pictureBox32.Image = getImg(px + 0, py + 1);
            //        pictureBox33.Image = getImg(px + 1, py + 1);
            //        //pictureBox11.Image = getImg(px, py - 1);
            //        //pictureBox12.Image = getImg(px + 1, py - 1);
            //        //pictureBox21.Image = getImg(px, py);
            //        //pictureBox22.Image = getImg(px + 1, py);
            //        //pictureBox11.Location = new Point(120 - mx, -136 - my);
            //        //pictureBox12.Location = new Point(376 - mx, -136 - my);
            //        //pictureBox21.Location = new Point(120 - mx, 120 - my);
            //        //pictureBox22.Location = new Point(376 - mx, 120 - my);
            //    }
            //}
            //else
            //{
            //    if (my > 128)
            //    {
            //        pictureBox11.Image = getImg(px - 1, py - 1);
            //        pictureBox12.Image = getImg(px + 0, py - 1);
            //        pictureBox13.Image = getImg(px + 1, py - 1);
            //        pictureBox21.Image = getImg(px - 1, py);
            //        pictureBox22.Image = getImg(px + 0, py);
            //        pictureBox23.Image = getImg(px + 1, py);
            //        pictureBox31.Image = getImg(px - 1, py + 1);
            //        pictureBox32.Image = getImg(px + 0, py + 1);
            //        pictureBox33.Image = getImg(px + 1, py + 1);
                   
            //        //pictureBox11.Image = getImg(px - 1, py);
            //        //pictureBox12.Image = getImg(px, py);
            //        //pictureBox21.Image = getImg(px - 1, py + 1);
            //        //pictureBox22.Image = getImg(px, py + 1);
            //        //pictureBox11.Location = new Point(-136 - mx, 120 - my);
            //        //pictureBox12.Location = new Point(120 - mx, 120 - my);
            //        //pictureBox21.Location = new Point(-136 - mx, 376 - my);
            //        //pictureBox22.Location = new Point(120 - mx, 376 - my);
            //    }
            //    else
            //    {
            //        pictureBox11.Image = getImg(px - 1, py - 1);
            //        pictureBox12.Image = getImg(px + 0, py - 1);
            //        pictureBox13.Image = getImg(px + 1, py - 1);
            //        pictureBox21.Image = getImg(px - 1, py);
            //        pictureBox22.Image = getImg(px + 0, py);
            //        pictureBox23.Image = getImg(px + 1, py);
            //        pictureBox31.Image = getImg(px - 1, py + 1);
            //        pictureBox32.Image = getImg(px + 0, py + 1);
            //        pictureBox33.Image = getImg(px + 1, py + 1);
                   
            //        //pictureBox11.Image = getImg(px - 1, py - 1);
            //        //pictureBox12.Image = getImg(px, py - 1);
            //        //pictureBox21.Image = getImg(px - 1, py);
            //        //pictureBox22.Image = getImg(px, py);
            //        //pictureBox11.Location = new Point(-136 - mx, -136 - my);
            //        //pictureBox12.Location = new Point(120 - mx, -136 - my);
            //        //pictureBox21.Location = new Point(-136 - mx, 120 - my);
            //        //pictureBox22.Location = new Point(120 - mx, 120 - my);
            //    }
            //}

            textBox1.Text = _count.ToString();

            labelX.Text = convDo(_dx, "EW");
            labelY.Text = convDo(_dy, "SN");
            
        }

        private static string convDo(double v, string sn)
        {
            string ns = (v < 0) ? sn.Substring(0, 1) : sn.Substring(1, 1);
            double vs = Math.Abs(v);
            int vint = (int)vs;
            double vmin = (vs - vint) * 60;
            int vminint = (int)vmin;
            double vsec = (vmin - vminint) * 60;
            string txt = ns + vint.ToString() + "." + vminint.ToString() + "'" + vsec.ToString() + "\"";
            return txt;
        }

        private Image getImg(int px, int py)
        {
            px %= 2 << (_lv - 1);

            //\Storage Card\ta_lv08\
            //\기억장치카드\
            string fileName = String.Format("{0}lv{1:D2}\\lv{1:D2}y{2:D3}x{3:D3}.png", _mapDir, _lv, py, px);

            Image img = null;
            try
            {
                img = new Bitmap(fileName);
            }
            catch (Exception ee)
            {
                if (_netConnect && getImg(fileName, py, px))
                {
                    try
                    {
                        img = new Bitmap(fileName);
                    }
                    catch
                    {
                    }
                }
            }
            return img;
        }

        private bool getImg(string fileName, int yy, int xx)
        {
            try
            {
                _count++;
                string url = String.Format("http://mt1.google.com/mt/v=w2.95&hl=en&x={2}&y={1}&z={0}", _lv, yy, xx);
                if (_lv >= 7)
                {
                    int kxst = 111079 / (1 << (17 - _lv));
                    int kxen = 113212 / (1 << (17 - _lv));
                    int kyst = 50269 / (1 << (17 - _lv));
                    int kyen = 52748 / (1 << (17 - _lv));
                    if (yy >= kyst && yy < kyen && xx >= kxst && xx < kxen)
                    {
                        url = String.Format("http://mt0.gmaptiles.co.kr/mt?hl=en&x={2}&y={1}&z={0}", _lv, yy, xx);
                    }
                }
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Credentials = CredentialCache.DefaultCredentials;
                request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; ko; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 (.NET CLR 3.5.30729)";
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                Stream dataStream = response.GetResponseStream();

                FileStream fs = File.Create(fileName);
                //byte[] buf = new byte[100000];
                //int len = dataStream.Read(buf, 0, 100000);
                //fs.Write(buf, 0, len);

                //int b;
                //while ((b = dataStream.ReadByte()) != -1)
                //{
                //    fs.WriteByte((byte)b);
                //}
                int readLen;
                byte[] buf = new byte[1024];
                while ((readLen = dataStream.Read(buf, 0, 1024)) != 0)
                {
                    fs.Write(buf, 0, readLen);
                }


                fs.Close();
                dataStream.Close();
            }
            catch (Exception ee)
            {
                return false;
            }
            return true;
        }

        private void lvChange(object sender, int newLv)
        {
            menuItem2.Checked = false;
            menuItem3.Checked = false;
            menuItem4.Checked = false;
            menuItem5.Checked = false;
            menuItem6.Checked = false;
            menuItem7.Checked = false;
            menuItem8.Checked = false;
            menuItem9.Checked = false;
            menuItem10.Checked = false;
            menuItem11.Checked = false;
            menuItem12.Checked = false;
            menuItem13.Checked = false;
            menuItem14.Checked = false;
            menuItem15.Checked = false;
            menuItem16.Checked = false;

            MenuItem item = (MenuItem)sender;
            item.Checked = true;
            //double sc = Math.Pow((double)2, (double)newLv - lv);
            //px = (int)(px * sc);
            //py = (int)(py * sc);
            _lv = newLv;
            mapShow();
        }

        private void menuItem2_Click(object sender, EventArgs e)
        {
            lvChange(sender, 3);
        }

        private void menuItem3_Click(object sender, EventArgs e)
        {
            lvChange(sender, 4);
        }

        private void menuItem4_Click(object sender, EventArgs e)
        {
            lvChange(sender, 5);
        }

        private void menuItem5_Click(object sender, EventArgs e)
        {
            lvChange(sender, 6);
        }

        private void menuItem6_Click(object sender, EventArgs e)
        {
            lvChange(sender, 7);
        }

        private void menuItem7_Click(object sender, EventArgs e)
        {
            lvChange(sender, 8);
        }

        private void menuItem8_Click(object sender, EventArgs e)
        {
            lvChange(sender, 9);
        }

        private void menuItem9_Click(object sender, EventArgs e)
        {
            lvChange(sender, 10);
        }

        private void menuItem10_Click(object sender, EventArgs e)
        {
            lvChange(sender, 11);
        }

        private void menuItem11_Click(object sender, EventArgs e)
        {
            lvChange(sender, 12);
        }

        private void menuItem12_Click(object sender, EventArgs e)
        {
            lvChange(sender, 13);
        }

        private void menuItem13_Click(object sender, EventArgs e)
        {
            lvChange(sender, 14);
        }

        private void menuItem14_Click(object sender, EventArgs e)
        {
            lvChange(sender, 15);
        }

        private void menuItem15_Click(object sender, EventArgs e)
        {
            lvChange(sender, 16);
        }

        private void menuItem16_Click(object sender, EventArgs e)
        {
            lvChange(sender, 17);
        }

        private void menuItem18_Click(object sender, EventArgs e)
        {
            Conf conf = new Conf();

            conf.textBoxMapDir.Text = _mapDir;
            conf.comboBoxPort.Text = _gpsPort;
            conf.comboBoxSpeed.Text = _gpsSpeed;

            if (conf.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            _mapDir = conf.textBoxMapDir.Text;
            _gpsPort = conf.comboBoxPort.Text;
            _gpsSpeed = conf.comboBoxSpeed.Text;

            saveSetting();
            gpsSetting();
            
        }

        private void pictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            PictureBox pBox = (PictureBox)sender;
            int mx = pBox.Location.X + e.X - 576;
            int my = pBox.Location.Y + e.Y - 576;

            double lim = (2 << (_lv - 1)) * 256;

            double x = (0.5 - _dx / 360) * lim;

            double phi = Math.PI * _dy / 180;
            double dv = 0.5 * Math.Log((1 + Math.Sin(phi)) / (1 - Math.Sin(phi)));
            double y = (1 - dv / Math.PI) / 2 * lim;

            x += mx;
            y += my;

            _dx = (0.5 - (x / lim)) * 360;

            dv = (1 - y / lim * 2) * Math.PI;
            phi = Math.Asin((Math.Exp(dv * 2) - 1) / ((Math.Exp(dv * 2) + 1)));
            _dy = phi * 180 / Math.PI;

            mapShow();
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            int recv = 0;
            string[] gpgga = new string[15];
            string[] gprmc = new string[10];
            while (recv != 3)
            {
                try
                {
                    string inStr = serialPort1.ReadLine();
                    if (inStr.StartsWith("$GPGGA,"))
                    {
                        gpgga = inStr.Split(',');
                        if (gpgga.Length < 15)
                        {
                            return;
                        }
                        recv |= 1;
                    }

                    if (inStr.StartsWith("$GPRMC,"))
                    {
                        gprmc = inStr.Split(',');
                        if (gprmc.Length < 10)
                        {
                            return;
                        }
                        recv |= 2;
                    }
                }
                catch
                {
                    return;
                }
            }

            double y, x;
            try
            {
                dt = new DateTime(int.Parse(gprmc[9].Substring(4, 2)), int.Parse(gprmc[9].Substring(2, 2)), int.Parse(gprmc[9].Substring(0, 2)), int.Parse(gprmc[1].Substring(0, 2)), int.Parse(gprmc[1].Substring(2, 2)), int.Parse(gprmc[1].Substring(4, 2)), DateTimeKind.Utc);

                double vv = double.Parse(gpgga[2]);
                y = (vv / 100 - ((int)vv / 100)) / 0.6 + (int)vv / 100;
                y = (gpgga[3] == "N") ? y : (-y);
                double hh = double.Parse(gpgga[4]);
                x = (hh / 100 - ((int)hh / 100)) / 0.6 + (int)hh / 100;
                x = (gpgga[5] == "W") ? x : (-x);
                gps = int.Parse(gpgga[6]);
                num = int.Parse(gpgga[7]);
                if (gps == 0)
                {
                    hdop = -1;
                    if (y > 80 || y < -80)
                    {
                        return;
                    }
                }
                else
                {
                    hdop = double.Parse(gpgga[8]);
                    hight = double.Parse(gpgga[9]);
                    hightdiff = double.Parse(gpgga[11]);
                }

                velocity = double.Parse(gprmc[7]) * 1.8;
                degree = double.Parse(gprmc[8]);
            }
            catch
            {
                hdop = -1;
                return;
            }

            _dx = x;
            _dy = y;
            _change = true;
        }

        private void menuItem19_Click(object sender, EventArgs e)
        {
            if (menuItem19.Checked)
            {
                serialPort1.Close();
                menuItem19.Checked = false;
            }
            else
            {
                try
                {
                    labelDt.Text = "Connecting...";
                    serialPort1.Open();
                    menuItem19.Checked = true;
                    labelDt.Text = "Connected!";
                }
                catch
                {
                    labelDt.Text = "Connection failed.";
                    menuItem19.Checked = false;
                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (_change)
            {
                _change = false;
                mapShow();
                labelDt.Text = dt.ToShortDateString() + " " + dt.ToShortTimeString();
                labelSt.Text = "ST:" + num.ToString();
                labelHdop.Text = "HDOP:" + hdop.ToString();
                labelHigh.Text = "고도:" + hight.ToString();
                labelDrg.Text = "각:" + degree.ToString();
                labelV.Text = "SP:" + velocity.ToString();
            }
        }

        private void menuItem20_Click(object sender, EventArgs e)
        {
            saveSetting();
            Application.Exit();
        }

        private void menuItem21_Click(object sender, EventArgs e)
        {
            if (menuItem21.Checked)
            {
                _netConnect = false;
                menuItem21.Checked = false;
            }
            else
            {
                _netConnect = true;
                menuItem21.Checked = true;
            }
        }

        
    }
}